﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace NumberParser.Tests
{
    [TestClass]
    public class UnitTests
    {
        [TestMethod]
        public void Cannot_parse_empty_or_null()
        {
            double value;
            Assert.IsFalse(Parser.TryParse(string.Empty, out value));
            Assert.IsFalse(Parser.TryParse("", out value));
            Assert.IsFalse(Parser.TryParse(null, out value));
            Assert.IsFalse(Parser.TryParse(default(string), out value));
        }

        [TestMethod]
        public void Can_parse_positive_base_10_integers()
        {
            for (int value = 0; value < 10000; value++)
            {
                Assert.AreEqual(value, Parser.Parse(value.ToString()));
            }
        }

        [TestMethod]
        public void Can_parse_negative_base_10_integers()
        {
            for (int value = -10000; value < 0; value++)
            {
                Assert.AreEqual(value, Parser.Parse(value.ToString()));
            }
        }

        [TestMethod]
        public void Negative_sign_cannot_be_after_first_digit()
        {
            double value;
            Assert.IsFalse(Parser.TryParse("1-2345", out value));
            Assert.IsFalse(Parser.TryParse("12-345", out value));
            Assert.IsFalse(Parser.TryParse("123-45", out value));
            Assert.IsFalse(Parser.TryParse("1234-5", out value));
            Assert.IsFalse(Parser.TryParse("12345-", out value));
        }

        [TestMethod]
        public void Exponent_value_raises_number_by_a_power_of_ten()
        {
            for (int value = 0; value < 10; value++)
            {
                Assert.AreEqual(12345 * Math.Pow(10, value), Parser.Parse("12345#" + value.ToString()));
            }
        }

        public void Exponent_cannot_be_negative()
        {
            double value;
            for (int exponent = -10; exponent < 0; exponent++)
            {
                Assert.IsFalse(Parser.TryParse("12345#" + exponent.ToString(), out value));
            }
        }

        [TestMethod]
        public void Exponent_can_only_occur_once()
        {
            double value;
            Assert.IsFalse(Parser.TryParse("123#104#61", out value));
        }

        [TestMethod]
        public void Can_parse_positive_base_10_decimal_numbers()
        {
            for (double value = 0; value < 1; value += 0.001)
            {
                /* The reason for the call to Math.Round().
                 * 
                 * When adding decimal numbers together, you will sometimes get addition artifacts.
                 * i.e. 0.008 + 0.001 = 0.009000000000011...
                 * This is due to the fact that while we think in decimal, the computer thinks in binary.
                 * The rounding function corrects the error.
                 */
                value = Math.Round(value, 3);

                Assert.AreEqual(value, Parser.Parse(value.ToString()));
            }
        }

        [TestMethod]
        public void Can_parse_base_16_number()
        {
            Assert.AreEqual(0xABCD, Parser.Parse("16@ABCD")); // test upper-case
            Assert.AreEqual(0xABCD, Parser.Parse("16@abcd")); // test lower-case
            Assert.AreEqual(0xABCD, Parser.Parse("16@aBcD")); // test mixed-case
        }

        [TestMethod]
        public void Radix_must_be_between_1_and_36()
        {
            double value;
            for (int radix = -37; radix <= 0; radix++)
            {
                Assert.IsFalse(Parser.TryParse(radix.ToString() + "@0", out value));
            }
            for (int radix = 1; radix <= 36; radix++)
            {
                Assert.IsTrue(Parser.TryParse(radix.ToString() + "@0", out value));
            }
            Assert.IsFalse(Parser.TryParse("37@0", out value));
        }
    }
}